# CMakeLists.txt
#
# Wireshark - Network traffic analyzer
# By Gerald Combs <gerald@wireshark.org>
# Copyright 1998 Gerald Combs
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

# We should use CPack to help generate a .msi using WIX.

set(WIX_GENERATED_FILES
	${CMAKE_CURRENT_BINARY_DIR}/DependentComponents.wxs
	${CMAKE_CURRENT_BINARY_DIR}/Diameter.wxs
	${CMAKE_CURRENT_BINARY_DIR}/QtDependentComponents.wxs
	${CMAKE_CURRENT_BINARY_DIR}/QtTranslation.wxs
	${CMAKE_CURRENT_BINARY_DIR}/RadiusDict.wxs
	${CMAKE_CURRENT_BINARY_DIR}/SNMPMibs.wxs
	${CMAKE_CURRENT_BINARY_DIR}/UsersGuide.wxs
)
set(WIX_GENERATED_FILES ${WIX_GENERATED_FILES} PARENT_SCOPE)

set(WIX_SOURCE_FILES
	${CMAKE_SOURCE_DIR}/packaging/wix/Wireshark.wxs
	${CMAKE_SOURCE_DIR}/packaging/wix/WiresharkOptionsDlg.wxs
	${CMAKE_SOURCE_DIR}/packaging/wix/WiresharkWixUI.wxs
	${WIX_GENERATED_FILES}
)
set(WIX_SOURCE_FILES ${WIX_SOURCE_FILES} PARENT_SCOPE)

set(WIX_FILES
	ComponentGroups.wxi
	COPYING.rtf
	DirectoryStructure.wxi
	Features.wxi
	InputPaths.wxi
	Plugins.wxi
	Prerequisites.wxi
	UserInterface.wxi
	${WIX_SOURCE_FILES}
	PARENT_SCOPE
)

set(WIX_OUT_FILES
	${CMAKE_CURRENT_BINARY_DIR}/DependentComponents.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/Diameter.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/QtDependentComponents.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/QtTranslation.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/RadiusDict.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/SNMPMibs.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/UsersGuide.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/Wireshark.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/WiresharkOptionsDlg.wixobj
	${CMAKE_CURRENT_BINARY_DIR}/WiresharkWixUI.wixobj
)
set(WIX_OUT_FILES ${WIX_OUT_FILES} PARENT_SCOPE)

# Variables required for Wireshark.wxs
set(PROGRAM_NAME ${CMAKE_PROJECT_NAME})
file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}" TOP_SRC_DIR)
# STAGING_DIR depends on the build configuration so we pass it
# on the command line below.
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/doc" DOC_DIR)

# To do:
# - Sync the various version names between CMake and Wix.
# - Set CMakeLists.txt version strings in tools/make-version.py
# - Add a VERSION_EXTRA cmake option
set (VERSION "${PROJECT_VERSION}")
set(PRODUCT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_PATCH_VERSION}.${PROJECT_BUILD_VERSION})

# Use the merge module that comes with our version of Visual Studio
if(MSVC_VERSION GREATER_EQUAL 1930)
	set (MSVC_CRT_VERSION "VC143")
elseif(MSVC_VERSION GREATER_EQUAL 1920)
	set (MSVC_CRT_VERSION "VC142")
elseif(MSVC_VERSION GREATER_EQUAL 1910)
	set (MSVC_CRT_VERSION "VC141")
elseif(MSVC_VERSION GREATER_EQUAL 1900)
	set (MSVC_CRT_VERSION "VC140")
endif()

# Starting with Visual Studio 2019 merge modules are deprecated but
# are available as an individual component.
# https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes#-deprecations
set(MERGE_MODULE "Microsoft_${MSVC_CRT_VERSION}_CRT_${WIRESHARK_TARGET_PLATFORM}.msm")
set (PF86_ENV "ProgramFiles(x86)")

set(VC_TOOLS_MERGE_MODULES_DIR)
if (DEFINED ENV{VCToolsRedistDir})
	set(VC_TOOLS_MERGE_MODULES_DIR "$ENV{VCToolsRedistDir}/MergeModules")
endif()

find_path(MERGE_MODULE_DIR ${MERGE_MODULE}
	PATHS
		#"$ENV{VCINSTALLDIR}/VC/Redist/MSVC/how-do-we-get-this-version/Merge Modules"
		${VC_TOOLS_MERGE_MODULES_DIR}
		"$ENV{${PF86_ENV}}/Common Files/Merge Modules"
		"$ENV{PROGRAMFILES}/Common Files/Merge Modules"
	NO_DEFAULT_PATH
)
file(TO_NATIVE_PATH "${MERGE_MODULE_DIR}/Microsoft_${MSVC_CRT_VERSION}_CRT_${WIRESHARK_TARGET_PLATFORM}.msm" MSM_NATIVE_PATH)
message(STATUS "Using ${MSM_NATIVE_PATH} for the WiX installer")

# DependentComponents.wxi. Can be created at configure time.
set(_all_manifest_wix "${CMAKE_CURRENT_BINARY_DIR}/DependentComponents.wxs")
file(WRITE "${_all_manifest_wix}" "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
file(APPEND "${_all_manifest_wix}" "<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n\n")
file(APPEND "${_all_manifest_wix}" "  <!-- Files required for all sections. Generated by CMake. -->\n")
file(APPEND "${_all_manifest_wix}"  "<?include InputPaths.wxi ?>\n")
file(APPEND "${_all_manifest_wix}" "  <Fragment>\n")
file(APPEND "${_all_manifest_wix}" "    <DirectoryRef Id=\"INSTALLFOLDER\">\n")
file(APPEND "${_all_manifest_wix}" "      <?ifdef BUNDLE_DEBUG_DLLS ?>\n")
foreach(_dll ${GLIB2_DLLS_DEBUG})
	STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
	file(APPEND "${_all_manifest_wix}" "        <Component Id=\"cmp${_wix_name}\" Guid=\"*\">\n")
	file(APPEND "${_all_manifest_wix}" "          <File Id=\"fil${_wix_name}\" KeyPath=\"yes\" Source=\"$(var.Staging.Dir)\\${_dll}\"/>\n")
	file(APPEND "${_all_manifest_wix}" "        </Component>\n")
endforeach()
file(APPEND "${_all_manifest_wix}" "      <?else?>\n")
foreach(_dll ${GLIB2_DLLS_RELEASE})
	STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
	file(APPEND "${_all_manifest_wix}" "        <Component Id=\"cmp${_wix_name}\" Guid=\"*\">\n")
	file(APPEND "${_all_manifest_wix}" "          <File Id=\"fil${_wix_name}\" KeyPath=\"yes\" Source=\"$(var.Staging.Dir)\\${_dll}\"/>\n")
	file(APPEND "${_all_manifest_wix}" "        </Component>\n")
endforeach()
file(APPEND "${_all_manifest_wix}" "      <?endif?>\n")
SET(unique_component "")
set (_dll_list ${AMRNB_DLL} ${CARES_DLL} ${PCRE2_RELEASE_DLL} ${GCRYPT_DLLS}
	${GNUTLS_DLLS} ${KERBEROS_DLLS} ${LIBSSH_DLLS} ${LUA_DLL}
	${LZ4_DLL} ${MINIZIP_DLL} ${MINIZIPNG_DLLS} ${NGHTTP2_DLL} ${NGHTTP3_DLL} ${SBC_DLL} ${SMI_DLL}
	${SNAPPY_DLL} ${SPANDSP_DLL} ${BCG729_DLL} ${LIBXML2_DLLS} ${WINSPARKLE_DLL}
	${XXHASH_DLL} ${ZLIB_DLL} ${ZLIBNG_DLL} ${BROTLI_DLLS} ${ZSTD_DLL} ${ILBC_DLL} ${OPUS_DLL}
	${SPEEXDSP_DLL}
	# Required for mmdbresolve
	${MAXMINDDB_DLL}
	)
foreach(_dll ${_dll_list})
	#ensure uniqueness of files
	IF(NOT "${unique_component}" MATCHES "(^|;)${_dll}(;|$)")
		STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
		file(APPEND "${_all_manifest_wix}" "      <Component Id=\"cmp${_wix_name}\" Guid=\"*\">\n")
		file(APPEND "${_all_manifest_wix}" "        <File Id=\"fil${_wix_name}\" KeyPath=\"yes\" Source=\"$(var.Staging.Dir)\\${_dll}\"/>\n")
		file(APPEND "${_all_manifest_wix}" "      </Component>\n")
		SET(unique_component ${unique_component} ${_dll})
	ENDIF(NOT "${unique_component}" MATCHES "(^|;)${_dll}(;|$)")
endforeach()
file(APPEND "${_all_manifest_wix}" "    </DirectoryRef>\n")
file(APPEND "${_all_manifest_wix}" "  </Fragment>\n")
file(APPEND "${_all_manifest_wix}" "  <Fragment>\n")
file(APPEND "${_all_manifest_wix}" "    <ComponentGroup Id=\"CG.RequiredDependencies\">\n")
file(APPEND "${_all_manifest_wix}" "      <?ifdef BUNDLE_DEBUG_DLLS ?>\n")
foreach(_dll ${GLIB2_DLLS_DEBUG})
	STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
	file(APPEND "${_all_manifest_wix}" "        <ComponentRef Id=\"cmp${_wix_name}\" />\n")
endforeach()
file(APPEND "${_all_manifest_wix}" "      <?else?>\n")
foreach(_dll ${GLIB2_DLLS_RELEASE})
	STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
	file(APPEND "${_all_manifest_wix}" "        <ComponentRef Id=\"cmp${_wix_name}\" />\n")
endforeach()
file(APPEND "${_all_manifest_wix}" "      <?endif?>\n")
SET(unique_file "")
foreach(_dll ${_dll_list})
	#ensure uniqueness of files
	IF(NOT "${unique_file}" MATCHES "(^|;)${_dll}(;|$)")
		STRING(REGEX REPLACE "[-|\\.]" "_" _wix_name ${_dll})
		file(APPEND "${_all_manifest_wix}" "      <ComponentRef Id=\"cmp${_wix_name}\" />\n")
		SET(unique_file ${unique_file} ${_dll})
	ENDIF(NOT "${unique_file}" MATCHES "(^|;)${_dll}(;|$)")
endforeach()
file(APPEND "${_all_manifest_wix}" "    </ComponentGroup>\n")
file(APPEND "${_all_manifest_wix}" "  </Fragment>\n")
file(APPEND "${_all_manifest_wix}" "\n</Wix>\n")

if(SMI_DIR)
	set(d_smi_dir "-dSMI_DIR")
endif()

if (MAXMINDDB_FOUND)
	set(d_mmdbresolve_exe "-dMMDBRESOLVE_EXE")
endif()

set(WIX_CANDLE_DEFINES
	-v
	-sw1076
	-dPlatform=${WIRESHARK_TARGET_PLATFORM}
	-dWiresharkName=${CMAKE_PROJECT_NAME}
	-dWiresharkVersion=${PRODUCT_VERSION}
	-dWiresharkMajorVersion=${PROJECT_MAJOR_VERSION}
	-dWiresharkMinorVersion=${PROJECT_MINOR_VERSION}
	-dAssetDir=${CMAKE_SOURCE_DIR}/packaging/wix
	-dBuildOutputDir=${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}
	-dDiameterDir=${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/diameter
	-dIconDir=${CMAKE_SOURCE_DIR}/resources/icons
	-dQtTranslationDir=${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/translations
	-dRadiusDictDir=${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/radius
	-dSnmpMibDir=${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/snmp/mibs
	-dUsersGuideDir=${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/doc/wsug_html_chunked
	-dVCRedistVersion=${MSVC_CRT_VERSION}
	-dVCRedistDir=${MERGE_MODULE_DIR}
	${d_smi_dir}
	${d_mmdbresolve_exe}
	-arch ${WIRESHARK_TARGET_PLATFORM}
	-ext WixUIExtension
	-I${CMAKE_SOURCE_DIR}/packaging/wix
	-out ${CMAKE_CURRENT_BINARY_DIR}/
	PARENT_SCOPE
)

# The NSIS CMakeFile sets the program name + version slightly differently.
set(WIX_LIGHT_DEFINES
	-v
	-out ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}-${WIRESHARK_TARGET_PLATFORM}.msi
	-sw1076
	-ext WixUIExtension
	-loc ${CMAKE_CURRENT_SOURCE_DIR}/StringOverrides.wxl
	PARENT_SCOPE
)

set(WIX_HEAT_FLAGS
	-v
	-ag
	-nologo
	-srd
	-sreg
	PARENT_SCOPE
)

macro( ADD_WIX_PACKAGE_TARGET )
	#
	# XXX - if we're not building Wireshark, we can't build
	# QtDependentComponents.wxs..  On the other hand, if we're
	# not building Wireshark, we have no need to include Qt
	# in the installer, so it's not clear we need that file.
	#
	# This should probably be fixed, so that people can produce
	# command-line-only installer packages.
	if(BUILD_wireshark)
		set (_wix_source_dir ${CMAKE_SOURCE_DIR}/packaging/wix )
		set (_wix_binary_dir ${CMAKE_BINARY_DIR}/packaging/wix )

		# QtDependentComponents.wxs. Created using Wireshark.exe.
		add_custom_command(OUTPUT ${_wix_binary_dir}/QtDependentComponents.wxs
			COMMAND set "PATH=${QT_BIN_PATH};%PATH%"
			COMMAND ${POWERSHELL_COMMAND} "${_wix_source_dir}/windeployqt-to-wix.ps1"
				-Executable $<TARGET_FILE:wireshark>
				-FilePath ${_wix_binary_dir}/QtDependentComponents.wxs
			DEPENDS "${_wix_source_dir}/windeployqt-to-wix.ps1"
		)

		# UsersGuide.wxs. Collects the contents of wsug_html_chunked.
		# Generated with heat.exe
		add_custom_command(OUTPUT ${_wix_binary_dir}/UsersGuide.wxs
			COMMAND ${WIX_HEAT_EXECUTABLE} dir ${CMAKE_BINARY_DIR}/doc/wsug_html_chunked
					${WIX_HEAT_FLAGS} -cg CG.Documentation -dr dirUsersGuide -var var.UsersGuideDir
					-out ${_wix_binary_dir}/UsersGuide.wxs
		)

		# SNMPMibs.wxs. Collects all MIBs in "output" snmp/mibs
		# directory. Generated with heat.exe
		add_custom_command(OUTPUT ${_wix_binary_dir}/SNMPMibs.wxs
			COMMAND ${WIX_HEAT_EXECUTABLE} dir ${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/snmp/mibs
					${WIX_HEAT_FLAGS} -cg CG.Plugins.SNMP -dr dirSnmpMibs -var var.SnmpMibDir
					-out ${_wix_binary_dir}/SNMPMibs.wxs
		)

		# RadiusDict.wxs. Collects all Radius dictionary files in
		# "output" radius directory. Generated with heat.exe
		add_custom_command(OUTPUT ${_wix_binary_dir}/RadiusDict.wxs
			COMMAND ${WIX_HEAT_EXECUTABLE} dir ${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/radius
					${WIX_HEAT_FLAGS} -cg CG.RadiusDict -dr dirRadius -var var.RadiusDictDir
					-out ${_wix_binary_dir}/RadiusDict.wxs
		)

		# Diameter.wxs. Collects all Diameter XML dictionary files
		# in "output" diameter directory. Generated with heat.exe
		add_custom_command(OUTPUT ${_wix_binary_dir}/Diameter.wxs
			COMMAND ${WIX_HEAT_EXECUTABLE} dir ${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/diameter
					${WIX_HEAT_FLAGS} -cg CG.Diameter -dr dirDiameter -var var.DiameterDir
					-out ${_wix_binary_dir}/Diameter.wxs
		)

		# QtTranslation.wxs. Collects all Qt translation files in
		# "output" translations directory. Generated with heat.exe
		add_custom_command(OUTPUT ${_wix_binary_dir}/QtTranslation.wxs
			COMMAND ${WIX_HEAT_EXECUTABLE} dir ${ARCHIVE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/translations
					${WIX_HEAT_FLAGS} -cg CG.QtTranslations -dr dirTranslations -var var.QtTranslationDir
					-out ${_wix_binary_dir}/QtTranslation.wxs
		)

		# Build WiX package dependencies. We build the package in
		# two stages so that wireshark_wix below doesn't trigger any
		# dependencies that might clobber any signed executables.
		# XXX Rename this to wireshark_wix_prep
		add_custom_target(wireshark_wix_prep
			DEPENDS
				${WIX_FILES}
				copy_data_files
				user_guide_html
				release_notes_html
		)
		set_target_properties(wireshark_wix_prep PROPERTIES
			FOLDER "Packaging"
			EXCLUDE_FROM_DEFAULT_BUILD True
		)

		# Dump the installer into
		# ${CMAKE_CURRENT_SOURCE_DIR}/packaging/wix
		# Note that executables and DLLs *must* be built separately
		# XXX Rename this to wireshark_wix
		add_custom_target(wireshark_wix
			COMMAND ${WIX_CANDLE_EXECUTABLE} ${WIX_CANDLE_DEFINES}
				$<$<CONFIG:Debug>:-dBUNDLE_DEBUG_DLLS>
				${WIX_SOURCE_FILES}
			WORKING_DIRECTORY ${_wix_source_dir}

			COMMAND ${WIX_LIGHT_EXECUTABLE} ${WIX_LIGHT_DEFINES} ${WIX_OUT_FILES}
			WORKING_DIRECTORY ${_wix_binary_dir}
		)
		set_target_properties(wireshark_wix PROPERTIES
			FOLDER "Packaging"
			EXCLUDE_FROM_DEFAULT_BUILD True
		)
	else()
		message(WARNING "The WiX installer cannot be built if the Wireshark program isn't built.")
	endif()
endmacro( ADD_WIX_PACKAGE_TARGET )

set(CLEAN_FILES
	DependentComponents.wxs
	QtDependentComponents.wxs
	UsersGuide.wxs
	SNMPMibs.wxs
	RadiusDict.wxs
	Diameter.wxs
	QtTranslation.wxs
	wireshark-${VERSION}-${WIRESHARK_TARGET_PLATFORM}.msi
)
